From b3ade7c7f17c682c8f94a5b8d9ae2e2039ca7025 Mon Sep 17 00:00:00 2001 From: Florian Hahn Date: Thu, 16 Jul 2015 22:35:40 +0200 Subject: [PATCH] Add support for multiple -p options to `cargo {bench, build, doc}` --- src/bin/bench.rs | 6 +- src/bin/build.rs | 6 +- src/bin/doc.rs | 6 +- src/bin/run.rs | 2 +- src/bin/rustc.rs | 6 +- src/bin/test.rs | 6 +- src/cargo/ops/cargo_clean.rs | 2 +- src/cargo/ops/cargo_compile.rs | 121 +++++++++++++------- src/cargo/ops/cargo_doc.rs | 18 +-- src/cargo/ops/cargo_package.rs | 2 +- src/cargo/ops/cargo_rustc/compilation.rs | 9 +- src/cargo/ops/cargo_rustc/context.rs | 3 +- src/cargo/ops/cargo_rustc/mod.rs | 140 ++++++++++++----------- src/cargo/ops/cargo_test.rs | 41 +++++++ tests/test_cargo_compile.rs | 58 ++++++++++ tests/test_cargo_doc.rs | 45 ++++++++ tests/test_cargo_test.rs | 60 ++++++++++ 17 files changed, 393 insertions(+), 138 deletions(-) diff --git a/src/bin/bench.rs b/src/bin/bench.rs index 655fbff60..47150dfab 100644 --- a/src/bin/bench.rs +++ b/src/bin/bench.rs @@ -5,7 +5,7 @@ use cargo::util::important_paths::{find_root_manifest_for_cwd}; #[derive(RustcDecodable)] struct Options { flag_no_run: bool, - flag_package: Option, + flag_package: Vec, flag_jobs: Option, flag_features: Vec, flag_no_default_features: bool, @@ -26,7 +26,7 @@ pub const USAGE: &'static str = " Execute all benchmarks of a local package Usage: - cargo bench [options] [--] [...] + cargo bench [options] [-p SPEC --package SPEC]... [--] [...] Options: -h, --help Print this message @@ -75,7 +75,7 @@ pub fn execute(options: Options, config: &Config) -> CliResult> { target: options.flag_target.as_ref().map(|s| &s[..]), features: &options.flag_features, no_default_features: options.flag_no_default_features, - spec: options.flag_package.as_ref().map(|s| &s[..]), + spec: &options.flag_package, exec_engine: None, release: true, mode: ops::CompileMode::Bench, diff --git a/src/bin/build.rs b/src/bin/build.rs index 984a0e752..6140ca961 100644 --- a/src/bin/build.rs +++ b/src/bin/build.rs @@ -7,7 +7,7 @@ use cargo::util::{CliResult, CliError, Config}; #[derive(RustcDecodable)] struct Options { - flag_package: Option, + flag_package: Vec, flag_jobs: Option, flag_features: Vec, flag_no_default_features: bool, @@ -28,7 +28,7 @@ pub const USAGE: &'static str = " Compile a local package and all of its dependencies Usage: - cargo build [options] + cargo build [options] [-p SPEC --package SPEC]... Options: -h, --help Print this message @@ -72,7 +72,7 @@ pub fn execute(options: Options, config: &Config) -> CliResult> { target: options.flag_target.as_ref().map(|t| &t[..]), features: &options.flag_features, no_default_features: options.flag_no_default_features, - spec: options.flag_package.as_ref().map(|s| &s[..]), + spec: &options.flag_package, exec_engine: None, mode: ops::CompileMode::Build, release: options.flag_release, diff --git a/src/bin/doc.rs b/src/bin/doc.rs index 8fa2bae7c..8bc6289b5 100644 --- a/src/bin/doc.rs +++ b/src/bin/doc.rs @@ -15,14 +15,14 @@ struct Options { flag_release: bool, flag_quiet: bool, flag_color: Option, - flag_package: Option, + flag_package: Vec, } pub const USAGE: &'static str = " Build a package's documentation Usage: - cargo doc [options] + cargo doc [options] [-p SPEC --package SPEC]... Options: -h, --help Print this message @@ -62,7 +62,7 @@ pub fn execute(options: Options, config: &Config) -> CliResult> { target: options.flag_target.as_ref().map(|t| &t[..]), features: &options.flag_features, no_default_features: options.flag_no_default_features, - spec: options.flag_package.as_ref().map(|s| &s[..]), + spec: &options.flag_package, exec_engine: None, filter: ops::CompileFilter::Everything, release: options.flag_release, diff --git a/src/bin/run.rs b/src/bin/run.rs index c1c042958..2483dcc8d 100644 --- a/src/bin/run.rs +++ b/src/bin/run.rs @@ -68,7 +68,7 @@ pub fn execute(options: Options, config: &Config) -> CliResult> { target: options.flag_target.as_ref().map(|t| &t[..]), features: &options.flag_features, no_default_features: options.flag_no_default_features, - spec: None, + spec: &[], exec_engine: None, release: options.flag_release, mode: ops::CompileMode::Build, diff --git a/src/bin/rustc.rs b/src/bin/rustc.rs index 8a589091a..4b7121f43 100644 --- a/src/bin/rustc.rs +++ b/src/bin/rustc.rs @@ -8,7 +8,7 @@ use cargo::util::{CliResult, CliError, Config}; #[derive(RustcDecodable)] struct Options { arg_opts: Option>, - flag_package: Option, + flag_package: Vec, flag_jobs: Option, flag_features: Vec, flag_no_default_features: bool, @@ -29,7 +29,7 @@ pub const USAGE: &'static str = " Compile a package and all of its dependencies Usage: - cargo rustc [options] [--] [...] + cargo rustc [options] [-p SPEC --package SPEC]... [--] [...] Options: -h, --help Print this message @@ -75,7 +75,7 @@ pub fn execute(options: Options, config: &Config) -> CliResult> { target: options.flag_target.as_ref().map(|t| &t[..]), features: &options.flag_features, no_default_features: options.flag_no_default_features, - spec: options.flag_package.as_ref().map(|s| &s[..]), + spec: &options.flag_package, exec_engine: None, mode: ops::CompileMode::Build, release: options.flag_release, diff --git a/src/bin/test.rs b/src/bin/test.rs index ade460165..9b89fb912 100644 --- a/src/bin/test.rs +++ b/src/bin/test.rs @@ -10,7 +10,7 @@ struct Options { flag_manifest_path: Option, flag_no_default_features: bool, flag_no_run: bool, - flag_package: Option, + flag_package: Vec, flag_target: Option, flag_lib: bool, flag_bin: Vec, @@ -28,7 +28,7 @@ pub const USAGE: &'static str = " Execute all unit and integration tests of a local package Usage: - cargo test [options] [--] [...] + cargo test [options] [-p SPEC --package SPEC]... [--] [...] Options: -h, --help Print this message @@ -81,7 +81,7 @@ pub fn execute(options: Options, config: &Config) -> CliResult> { target: options.flag_target.as_ref().map(|s| &s[..]), features: &options.flag_features, no_default_features: options.flag_no_default_features, - spec: options.flag_package.as_ref().map(|s| &s[..]), + spec: &options.flag_package, exec_engine: None, release: options.flag_release, mode: ops::CompileMode::Test, diff --git a/src/cargo/ops/cargo_clean.rs b/src/cargo/ops/cargo_clean.rs index c3303423e..c3bc26827 100644 --- a/src/cargo/ops/cargo_clean.rs +++ b/src/cargo/ops/cargo_clean.rs @@ -49,7 +49,7 @@ pub fn clean(manifest_path: &Path, opts: &CleanOptions) -> CargoResult<()> { let profiles = Profiles::default(); let cx = try!(Context::new(&resolve, &srcs, &pkgs, opts.config, Layout::at(target_dir), - None, &pkg, BuildConfig::default(), + None, BuildConfig::default(), &profiles)); // And finally, clean everything out! diff --git a/src/cargo/ops/cargo_compile.rs b/src/cargo/ops/cargo_compile.rs index 74c073f26..41d0add87 100644 --- a/src/cargo/ops/cargo_compile.rs +++ b/src/cargo/ops/cargo_compile.rs @@ -28,7 +28,7 @@ use std::path::{Path, PathBuf}; use std::sync::Arc; use core::registry::PackageRegistry; -use core::{Source, SourceId, PackageSet, Package, Target}; +use core::{Source, SourceId, PackageSet, Package, Target, PackageId}; use core::{Profile, TargetKind}; use core::resolver::Method; use ops::{self, BuildOutput, ExecEngine}; @@ -47,7 +47,7 @@ pub struct CompileOptions<'a> { /// Flag if the default feature should be built for the root package pub no_default_features: bool, /// Root package to build (if None it's the current one) - pub spec: Option<&'a str>, + pub spec: &'a [String], /// Filter to apply to the root package to select which targets will be /// built. pub filter: CompileFilter<'a>, @@ -95,10 +95,10 @@ pub fn compile<'a>(manifest_path: &Path, compile_pkg(&package, options) } -pub fn compile_pkg<'a>(package: &Package, +pub fn compile_pkg<'a>(root_package: &Package, options: &CompileOptions<'a>) -> CargoResult> { - let CompileOptions { config, jobs, target, spec, features, + let CompileOptions { config, jobs, target, ref spec, features, no_default_features, release, mode, ref filter, ref exec_engine, ref target_rustc_args } = *options; @@ -108,7 +108,7 @@ pub fn compile_pkg<'a>(package: &Package, s.split(' ') }).map(|s| s.to_string()).collect::>(); - if spec.is_some() && (no_default_features || features.len() > 0) { + if spec.len() > 0 && (no_default_features || features.len() > 0) { return Err(human("features cannot be modified when the main package \ is not being built")) } @@ -116,14 +116,20 @@ pub fn compile_pkg<'a>(package: &Package, return Err(human("jobs must be at least 1")) } - let override_ids = try!(source_ids_from_config(config, package.root())); - let (packages, resolve_with_overrides, sources) = { - let mut registry = PackageRegistry::new(config); + let override_ids = + try!(source_ids_from_config(options.config, root_package.root())); + let mut registry = PackageRegistry::new(options.config); + if let Some(source) = source { + registry.preload(root_package.package_id().source_id(), source); + } else { + try!(registry.add_sources(&[root_package.package_id().source_id() + .clone()])); + } - // First, resolve the package's *listed* dependencies, as well as + // First, resolve the root_package's *listed* dependencies, as well as // downloading and updating all remotes and such. - let resolve = try!(ops::resolve_pkg(&mut registry, package)); + let resolve = try!(ops::resolve_pkg(&mut registry, root_package)); // Second, resolve with precisely what we're doing. Filter out // transitive dependencies if necessary, specify features, handle @@ -132,48 +138,82 @@ pub fn compile_pkg<'a>(package: &Package, try!(registry.add_overrides(override_ids)); - let method = Method::Required { + let method = Method::Required{ dev_deps: true, // TODO: remove this option? features: &features, - uses_default_features: !no_default_features, + uses_default_features: !options.no_default_features, }; let resolved_with_overrides = - try!(ops::resolve_with_previous(&mut registry, package, method, + try!(ops::resolve_with_previous(&mut registry, root_package, method, Some(&resolve), None)); - let packages = try!(ops::get_resolved_packages(&resolved_with_overrides, &mut registry)); + let req: Vec = resolved_with_overrides.iter().map(|r| { + r.clone() + }).collect(); + let packages = try!(registry.get(&req).chain_error(|| { + human("Unable to get packages from source") + })); (packages, resolved_with_overrides, registry.move_sources()) }; - let pkgid = match spec { - Some(spec) => try!(resolve_with_overrides.query(spec)), - None => package.package_id(), + let mut invalid_spec = vec![]; + let pkgids = if spec.len() > 0 { + spec.iter().filter_map(|p| { + match resolve_with_overrides.query(&p) { + Ok(p) => Some(p), + Err(..) => { invalid_spec.push(p.to_string()); None } + } + }).collect::>() + } else { + vec![root_package.package_id()] }; - let to_build = packages.iter().find(|p| p.package_id() == pkgid).unwrap(); - let targets = try!(generate_targets(to_build, mode, filter, release)); - - let target_with_args = match *target_rustc_args { - Some(args) if targets.len() == 1 => { - let (target, profile) = targets[0]; - let mut profile = profile.clone(); - profile.rustc_args = Some(args.to_vec()); - Some((target, profile)) - } - Some(_) => { - return Err(human("extra arguments to `rustc` can only be passed to \ - one target, consider filtering\nthe package by \ - passing e.g. `--lib` or `--bin NAME` to specify \ - a single target")) + + /* + if spec.len() > 0 && invalid_spec.len() > 0 { + return Err(human(format!("could not find package matching spec `{}`", + invalid_spec.join(", ")))); + } */ + + let to_builds = packages.iter().filter(|p| + pkgids.iter().find(|&op| *op == p.package_id()).is_some() + ).collect::>(); + + let mut twas = &mut vec![]; + let mut package_targets = vec![]; + + for &to_build in to_builds.iter() { + let targets = try!(generate_targets(to_build, mode, filter, release)); + + match *target_rustc_args { + Some(args) if targets.len() == 1 => { + let (target, profile) = targets[0]; + let mut profile = profile.clone(); + profile.rustc_args = Some(args.to_vec()); + twas.push((target, profile)); + } + Some(_) => { + return Err(human("extra arguments to `rustc` can only be \ + passed to one target, consider \ + filtering\nthe package by passing e.g. \ + `--lib` or `--bin NAME` to specify \ + a single target")) + } + None => package_targets.push((to_build, targets)), + }; + + } + + for targets in twas { + let (target, ref profile) = *targets; + for &to_build in to_builds.iter() { + package_targets.push((to_build, vec![(target, profile)])); } - None => None, - }; + } - let targets = target_with_args.as_ref().map(|&(t, ref p)| vec![(t, p)]) - .unwrap_or(targets); - let ret = { + let mut ret = { let _p = profile::start("compiling"); let mut build_config = try!(scrape_build_config(config, jobs, target)); build_config.exec_engine = exec_engine.clone(); @@ -182,15 +222,18 @@ pub fn compile_pkg<'a>(package: &Package, build_config.doc_all = deps; } - try!(ops::compile_targets(&targets, to_build, + try!(ops::compile_targets(&package_targets, &PackageSet::new(&packages), &resolve_with_overrides, &sources, config, build_config, - to_build.manifest().profiles())) + root_package.manifest().profiles(), + )) }; + ret.to_doc_test = to_builds.iter().map(|&p| p.clone()).collect(); + return Ok(ret); } diff --git a/src/cargo/ops/cargo_doc.rs b/src/cargo/ops/cargo_doc.rs index 11e5d5bf7..ca95b82a9 100644 --- a/src/cargo/ops/cargo_doc.rs +++ b/src/cargo/ops/cargo_doc.rs @@ -18,7 +18,7 @@ pub fn doc(manifest_path: &Path, let mut lib_names = HashSet::new(); let mut bin_names = HashSet::new(); - if options.compile_opts.spec.is_none() { + if options.compile_opts.spec.len() == 0 { for target in package.targets().iter().filter(|t| t.documented()) { if target.is_lib() { assert!(lib_names.insert(target.crate_name())); @@ -39,13 +39,15 @@ pub fn doc(manifest_path: &Path, try!(ops::compile(manifest_path, &options.compile_opts)); if options.open_result { - let name = match options.compile_opts.spec { - Some(spec) => try!(PackageIdSpec::parse(spec)).name().replace("-", "_").to_string(), - None => { - match lib_names.iter().chain(bin_names.iter()).nth(0) { - Some(s) => s.to_string(), - None => return Ok(()) - } + let name = if options.compile_opts.spec.len() > 0{ + // TODO + try!(PackageIdSpec::parse(options.compile_opts.spec.first() + .unwrap())).name().replace("-", "_") + .to_string() + } else { + match lib_names.iter().chain(bin_names.iter()).nth(0) { + Some(s) => s.to_string(), + None => return Ok(()) } }; diff --git a/src/cargo/ops/cargo_package.rs b/src/cargo/ops/cargo_package.rs index 64fc7e2ea..a1b3cd5af 100644 --- a/src/cargo/ops/cargo_package.rs +++ b/src/cargo/ops/cargo_package.rs @@ -214,7 +214,7 @@ fn run_verify(config: &Config, pkg: &Package, tar: &Path) target: None, features: &[], no_default_features: false, - spec: None, + spec: &[], filter: ops::CompileFilter::Everything, exec_engine: None, release: false, diff --git a/src/cargo/ops/cargo_rustc/compilation.rs b/src/cargo/ops/cargo_rustc/compilation.rs index bd6be3c4c..2404c1ede 100644 --- a/src/cargo/ops/cargo_rustc/compilation.rs +++ b/src/cargo/ops/cargo_rustc/compilation.rs @@ -17,7 +17,7 @@ pub struct Compilation<'cfg> { pub libraries: HashMap>, /// An array of all tests created during this compilation. - pub tests: Vec<(String, PathBuf)>, + pub tests: Vec<(Package, Vec<(String, PathBuf)>)>, /// An array of all binaries created. pub binaries: Vec, @@ -39,8 +39,7 @@ pub struct Compilation<'cfg> { /// be passed to future invocations of programs. pub extra_env: HashMap, - /// Top-level package that was compiled - pub package: Package, + pub to_doc_test: Vec, /// Features enabled during this compilation. pub features: HashSet, @@ -49,7 +48,7 @@ pub struct Compilation<'cfg> { } impl<'cfg> Compilation<'cfg> { - pub fn new(pkg: &Package, config: &'cfg Config) -> Compilation<'cfg> { + pub fn new(config: &'cfg Config) -> Compilation<'cfg> { Compilation { libraries: HashMap::new(), native_dirs: HashMap::new(), // TODO: deprecated, remove @@ -58,7 +57,7 @@ impl<'cfg> Compilation<'cfg> { tests: Vec::new(), binaries: Vec::new(), extra_env: HashMap::new(), - package: pkg.clone(), + to_doc_test: Vec::new(), features: HashSet::new(), config: config, } diff --git a/src/cargo/ops/cargo_rustc/context.rs b/src/cargo/ops/cargo_rustc/context.rs index 1ba892835..136997813 100644 --- a/src/cargo/ops/cargo_rustc/context.rs +++ b/src/cargo/ops/cargo_rustc/context.rs @@ -59,7 +59,6 @@ impl<'a, 'cfg> Context<'a, 'cfg> { config: &'cfg Config, host: Layout, target_layout: Option, - root_pkg: &Package, build_config: BuildConfig, profiles: &'a Profiles) -> CargoResult> { let target = build_config.requested_target.clone(); @@ -90,7 +89,7 @@ impl<'a, 'cfg> Context<'a, 'cfg> { host_dylib: host_dylib, host_exe: host_exe, requirements: HashMap::new(), - compilation: Compilation::new(root_pkg, config), + compilation: Compilation::new(config), build_state: Arc::new(BuildState::new(&build_config, deps)), build_config: build_config, exec_engine: engine, diff --git a/src/cargo/ops/cargo_rustc/mod.rs b/src/cargo/ops/cargo_rustc/mod.rs index a13a74dc0..1c2ad0705 100644 --- a/src/cargo/ops/cargo_rustc/mod.rs +++ b/src/cargo/ops/cargo_rustc/mod.rs @@ -54,8 +54,9 @@ pub struct TargetConfig { // Returns a mapping of the root package plus its immediate dependencies to // where the compiled libraries are all located. -pub fn compile_targets<'a, 'cfg: 'a>(targets: &[(&'a Target, &'a Profile)], - pkg: &'a Package, +pub fn compile_targets<'a, 'cfg: 'a>(pkg_targets: &'a [(&Package, + Vec<(&Target, + &'a Profile)>)], deps: &'a PackageSet, resolve: &'a Resolve, sources: &'a SourceMap<'cfg>, @@ -63,89 +64,97 @@ pub fn compile_targets<'a, 'cfg: 'a>(targets: &[(&'a Target, &'a Profile)], build_config: BuildConfig, profiles: &'a Profiles) -> CargoResult> { - if targets.is_empty() { - return Ok(Compilation::new(pkg, config)) - } - debug!("compile_targets: {}", pkg); + debug!("compile_targets: {}", pkg_targets.iter().map(|&(ref p, _)| p.name()) + .collect::>().join(", ")); try!(links::validate(deps)); let dest = if build_config.release {"release"} else {"debug"}; - let root = if resolve.root() == pkg.package_id() { - pkg - } else { - deps.iter().find(|p| p.package_id() == resolve.root()).unwrap() - }; + let root = deps.iter().find(|p| p.package_id() == resolve.root()).unwrap(); let host_layout = Layout::new(config, root, None, &dest); let target_layout = build_config.requested_target.as_ref().map(|target| { layout::Layout::new(config, root, Some(&target), &dest) }); let mut cx = try!(Context::new(resolve, sources, deps, config, - host_layout, target_layout, pkg, + host_layout, target_layout, build_config, profiles)); let mut queue = JobQueue::new(cx.resolve, deps, cx.jobs()); - // Prep the context's build requirements and see the job graph for all - // packages initially. { let _p = profile::start("preparing build directories"); - try!(cx.prepare(pkg, targets)); - prepare_init(&mut cx, pkg, &mut queue, &mut HashSet::new()); - custom_build::build_map(&mut cx, pkg, targets); + // Prep the context's build requirements and see the job graph for all + // packages initially. + for &(pkg, ref targets) in pkg_targets { + try!(cx.prepare(pkg, targets)); + prepare_init(&mut cx, pkg, &mut queue, &mut HashSet::new()); + custom_build::build_map(&mut cx, pkg, targets); + } } - // Build up a list of pending jobs, each of which represent compiling a - // particular package. No actual work is executed as part of this, that's - // all done next as part of the `execute` function which will run - // everything in order with proper parallelism. - try!(compile(targets, pkg, &mut cx, &mut queue)); + for &(pkg, ref targets) in pkg_targets { + // Build up a list of pending jobs, each of which represent + // compiling a particular package. No actual work is executed as + // part of this, that's all done next as part of the `execute` + // function which will run everything in order with proper + // parallelism. + try!(compile(targets, pkg, &mut cx, &mut queue)); + } // Now that we've figured out everything that we're going to do, do it! try!(queue.execute(cx.config)); - let out_dir = cx.layout(pkg, Kind::Target).build_out(pkg) - .display().to_string(); - cx.compilation.extra_env.insert("OUT_DIR".to_string(), out_dir); + for &(pkg, ref targets) in pkg_targets.iter() { + let out_dir = cx.layout(pkg, Kind::Target).build_out(pkg) + .display().to_string(); + cx.compilation.extra_env.insert("OUT_DIR".to_string(), out_dir); + + let mut tests = vec![]; + + for &(target, profile) in targets { + let kind = Kind::from(target); + for filename in try!(cx.target_filenames(pkg, target, profile, + kind)).iter() { + let dst = cx.out_dir(pkg, kind, target).join(filename); + if profile.test { + tests.push((target.name().to_string(), dst)); + } else if target.is_bin() || target.is_example() { + cx.compilation.binaries.push(dst); + } else if target.is_lib() { + let pkgid = pkg.package_id().clone(); + cx.compilation.libraries.entry(pkgid).or_insert(Vec::new()) + .push((target.clone(), dst)); + } + if !target.is_lib() { continue } - for &(target, profile) in targets { - let kind = Kind::from(target); - for filename in try!(cx.target_filenames(pkg, target, profile, - kind)).iter() { - let dst = cx.out_dir(pkg, kind, target).join(filename); - if profile.test { - cx.compilation.tests.push((target.name().to_string(), dst)); - } else if target.is_bin() || target.is_example() { - cx.compilation.binaries.push(dst); - } else if target.is_lib() { - let pkgid = pkg.package_id().clone(); - cx.compilation.libraries.entry(pkgid).or_insert(Vec::new()) - .push((target.clone(), dst)); - } - if !target.is_lib() { continue } + // Include immediate lib deps as well + for dep in &cx.dep_targets(pkg, target, kind, profile) { + let (pkg, target, profile) = *dep; + let pkgid = pkg.package_id(); + if !target.is_lib() { continue } + if profile.doc { continue } + if cx.compilation.libraries.contains_key(&pkgid) { + continue + } - // Include immediate lib deps as well - for dep in cx.dep_targets(pkg, target, kind, profile) { - let (pkg, target, profile) = dep; - let pkgid = pkg.package_id(); - if !target.is_lib() { continue } - if profile.doc { continue } - if cx.compilation.libraries.contains_key(&pkgid) { continue } - - let kind = kind.for_target(target); - let v = try!(cx.target_filenames(pkg, target, profile, kind)); - let v = v.into_iter().map(|f| { - (target.clone(), cx.out_dir(pkg, kind, target).join(f)) - }).collect::>(); - cx.compilation.libraries.insert(pkgid.clone(), v); + let kind = kind.for_target(target); + let v = + try!(cx.target_filenames(pkg, target, profile, kind)); + let v = v.into_iter().map(|f| { + (target.clone(), cx.out_dir(pkg, kind, target).join(f)) + }).collect::>(); + cx.compilation.libraries.insert(pkgid.clone(), v); + } } } - } - if let Some(feats) = cx.resolve.features(pkg.package_id()) { - cx.compilation.features.extend(feats.iter().cloned()); + cx.compilation.tests.push((pkg.clone(), tests)); + + if let Some(feats) = cx.resolve.features(pkg.package_id()) { + cx.compilation.features.extend(feats.iter().cloned()); + } } for (&(ref pkg, _), output) in cx.build_state.outputs.lock().unwrap().iter() { @@ -199,18 +208,17 @@ fn compile<'a, 'cfg>(targets: &[(&'a Target, &'a Profile)], }); // Figure out what stage this work will go into - let dst = match (target.is_lib(), + let stage = match (target.is_lib(), profile.test, target.is_custom_build()) { - (_, _, true) => jobs.queue(pkg, Stage::BuildCustomBuild), - (true, true, _) => jobs.queue(pkg, Stage::LibraryTests), - (false, true, _) => jobs.queue(pkg, Stage::BinaryTests), - (true, false, _) => jobs.queue(pkg, Stage::Libraries), - (false, false, _) if !target.is_bin() => { - jobs.queue(pkg, Stage::BinaryTests) - } - (false, false, _) => jobs.queue(pkg, Stage::Binaries), + (_, _, true) => Stage::BuildCustomBuild, + (true, true, _) => Stage::LibraryTests, + (false, true, _) => Stage::BinaryTests, + (true, false, _) => Stage::Libraries, + (false, false, _) if !target.is_bin() => Stage::BinaryTests, + (false, false, _) => Stage::Binaries, }; + let dst = jobs.queue(pkg, stage); dst.push((Job::new(dirty, fresh), freshness)); } diff --git a/src/cargo/ops/cargo_test.rs b/src/cargo/ops/cargo_test.rs index 555b239c0..51357eca1 100644 --- a/src/cargo/ops/cargo_test.rs +++ b/src/cargo/ops/cargo_test.rs @@ -169,3 +169,44 @@ fn run_doc_tests(options: &TestOptions, } Ok(errors) } + +fn build_and_run<'a>(manifest_path: &Path, + options: &TestOptions<'a>, + test_args: &[String]) + -> CargoResult, ProcessError>> { + let config = options.compile_opts.config; + let mut source = try!(PathSource::for_path(&manifest_path.parent().unwrap(), + config)); + try!(source.update()); + + let mut compile = try!(ops::compile(manifest_path, &options.compile_opts)); + if options.no_run { return Ok(Ok(compile)) } + compile.tests.iter_mut() + .map(|&mut (_, ref mut tests)| + tests.sort_by(|&(ref n1, _), &(ref n2, _)| n1.cmp(n2))) + .collect::>(); + + let cwd = config.cwd(); + for &(ref pkg, ref tests) in &compile.tests { + for &(_, ref exe) in tests { + let to_display = match util::without_prefix(exe, &cwd) { + Some(path) => path, + None => &**exe, + }; + let mut cmd = try!(compile.target_process(exe, pkg)); + cmd.args(test_args); + try!(config.shell().concise(|shell| { + shell.status("Running", to_display.display().to_string()) + })); + try!(config.shell().verbose(|shell| { + shell.status("Running", cmd.to_string()) + })); + match ExecEngine::exec(&mut ProcessEngine, cmd) { + Ok(()) => {} + Err(e) => return Ok(Err(e)) + } + } + } + + Ok(Ok(compile)) +} diff --git a/tests/test_cargo_compile.rs b/tests/test_cargo_compile.rs index b8930f2b8..87e47c2d4 100644 --- a/tests/test_cargo_compile.rs +++ b/tests/test_cargo_compile.rs @@ -1925,3 +1925,61 @@ test!(rustc_no_trans { assert_that(p.cargo("rustc").arg("-v").arg("--").arg("-Zno-trans"), execs().with_status(0)); }); + +test!(build_multiple_packages { + + + let p = project("foo") + .file("Cargo.toml", r#" + [package] + name = "foo" + version = "0.0.1" + authors = [] + + [dependencies.d1] + path = "d1" + [dependencies.d2] + path = "d2" + + [[bin]] + name = "foo" + "#) + .file("src/foo.rs", &main_file(r#""i am foo""#, &[])) + .file("d1/Cargo.toml", r#" + [package] + name = "d1" + version = "0.0.1" + authors = [] + + [[bin]] + name = "d1" + "#) + .file("d1/src/lib.rs", "") + .file("d1/src/main.rs", "fn main() { println!(\"d1\"); }") + .file("d2/Cargo.toml", r#" + [package] + name = "d2" + version = "0.0.1" + authors = [] + + [[bin]] + name = "d2" + doctest = false + "#) + .file("d2/src/main.rs", "fn main() { println!(\"d2\"); }"); + p.build(); + + assert_that(p.cargo_process("build").arg("-p").arg("d1").arg("-p").arg("d2").arg("-p").arg("foo"), execs()); + + assert_that(&p.bin("foo"), existing_file()); + assert_that(process(&p.bin("foo")).unwrap(), + execs().with_stdout("i am foo\n")); + + assert_that(&p.build_dir().join("debug").join("deps").join("d1"), existing_file()); + assert_that(process(&p.build_dir().join("debug").join("deps").join("d1")).unwrap(), + execs().with_stdout("d1")); + + assert_that(&p.build_dir().join("debug").join("deps").join("d2"), existing_file()); + assert_that(process(&p.build_dir().join("debug").join("deps").join("d2")).unwrap(), + execs().with_stdout("d2")); +}); diff --git a/tests/test_cargo_doc.rs b/tests/test_cargo_doc.rs index 57d37129d..935178379 100644 --- a/tests/test_cargo_doc.rs +++ b/tests/test_cargo_doc.rs @@ -432,3 +432,48 @@ test!(doc_release { {running} `rustdoc src[..]lib.rs [..]` ", compiling = COMPILING, running = RUNNING))); }); + +test!(doc_multiple_deps { + let p = project("foo") + .file("Cargo.toml", r#" + [package] + name = "foo" + version = "0.0.1" + authors = [] + + [dependencies.bar] + path = "bar" + + [dependencies.baz] + path = "baz" + "#) + .file("src/lib.rs", r#" + extern crate bar; + pub fn foo() {} + "#) + .file("bar/Cargo.toml", r#" + [package] + name = "bar" + version = "0.0.1" + authors = [] + "#) + .file("bar/src/lib.rs", r#" + pub fn bar() {} + "#) + .file("baz/Cargo.toml", r#" + [package] + name = "baz" + version = "0.0.1" + authors = [] + "#) + .file("baz/src/lib.rs", r#" + pub fn baz() {} + "#); + + assert_that(p.cargo_process("doc").arg("-p").arg("bar").arg("-p").arg("baz"), + execs().with_status(0)); + + assert_that(&p.root().join("target/doc"), existing_dir()); + assert_that(&p.root().join("target/doc/bar/index.html"), existing_file()); + assert_that(&p.root().join("target/doc/baz/index.html"), existing_file()); +}); diff --git a/tests/test_cargo_test.rs b/tests/test_cargo_test.rs index ab29bcc47..32787d998 100644 --- a/tests/test_cargo_test.rs +++ b/tests/test_cargo_test.rs @@ -1935,3 +1935,63 @@ test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured ", compiling = COMPILING, running = RUNNING, doctest = DOCTEST))) }); + +test!(test_multiple_packages { + let p = project("foo") + .file("Cargo.toml", r#" + [package] + name = "foo" + version = "0.0.1" + authors = [] + + [dependencies.d1] + path = "d1" + [dependencies.d2] + path = "d2" + + [lib] + name = "foo" + doctest = false + "#) + .file("src/lib.rs", "") + .file("d1/Cargo.toml", r#" + [package] + name = "d1" + version = "0.0.1" + authors = [] + + [lib] + name = "d1" + doctest = false + "#) + .file("d1/src/lib.rs", "") + .file("d2/Cargo.toml", r#" + [package] + name = "d2" + version = "0.0.1" + authors = [] + + [lib] + name = "d2" + doctest = false + "#) + .file("d2/src/lib.rs", ""); + p.build(); + + assert_that(p.cargo("test").arg("-p").arg("d1").arg("-p").arg("d2"), + execs().with_status(0) + .with_stdout_contains(&format!("\ +{running} target[..]debug[..]d1-[..] + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured +", running = RUNNING)) + .with_stdout_contains(&format!("\ +{running} target[..]debug[..]d2-[..] + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured +", running = RUNNING))); +}); -- 2.30.2